package com.yict.common.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <h3>Class name</h3> <h4>Description</h4>
 * 
 * <h4>Special Notes</h4>
 * 
 * 
 * @ver 1.0
 * @author Jay.Wu 2009-12-26
 * 
 */
public class ClassUtil {
	protected transient static final Log logger = LogFactory.getLog(ClassUtil.class);

	/**
	 * 将非空的属性值复制到另一个同属性的bean中
	 * 
	 * @param dest
	 * @param orig
	 * @author Jay.Wu
	 */
	public static void copyProperties(Object dest, Object orig) {
		Field[] fields = orig.getClass().getDeclaredFields();

		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			field.setAccessible(true);
			String filedName = field.getName();

			try {
				Object retobj = getFieldValue(orig, filedName);
				if (retobj == null) {
					continue;
				} else {
					setFieldValue(dest, filedName, retobj);
				}
			} catch (Exception e) {
				logger.error("", e);
			}
		}
	}

	/** */
	/**
	 * 调用类的方法，包括私有
	 * 
	 * @param Object
	 *            访问对象
	 * @param methodName
	 *            指定成员变量名
	 * @param type
	 *            方法参数类型
	 * @param value
	 *            方法参数值
	 * @return Object 方法的返回结果对象
	 * */
	public static Object useMethod(Object object, String methodName, Class<?>[] type, Object... value) {
		Class<?> classType = object.getClass();
		Method method = null;
		Object fildValue = null;

		try {
			method = classType.getDeclaredMethod(methodName, type);
			// 设置安全检查，访问私有成员方法必须
			method.setAccessible(true);
			fildValue = method.invoke(object, value);

		} catch (NoSuchMethodException e) {
			logger.error("", e);
		} catch (Exception e) {
			logger.error("", e);
		}

		return fildValue;
	}

	/**
	 * 直接取出变量值
	 * 
	 * @param dest
	 * @param filedName
	 * @return
	 * @author Jay.Wu
	 */
	public static Object getFieldValue(Object object, String filedName) {
		Object fildValue = null;

		try {
			fildValue = BeanUtils.getProperty(object, filedName);
		} catch (IllegalAccessException e) {
			logger.error(e.getMessage(), e);
		} catch (InvocationTargetException e) {
			logger.error(e.getMessage(), e);
		} catch (NoSuchMethodException e) {
			logger.warn(e.getMessage());
		}

		return fildValue;
	}

	/**
	 * 直接为变量赋值
	 * 
	 * @param obj
	 * @param filedName
	 * @param fieldValue
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @author Jay.Wu
	 */
	public static void setFieldValue(Object obj, String filedName, Object fieldValue) throws Exception {
		Field field = getField(obj, filedName);
		Class<?>[] types = new Class<?>[] { Long.class, Double.class };

		try {
			if (fieldValue != null) {
				if (!field.getType().getName().equals(fieldValue.getClass().getName())) {
					for (int i = 0; i < types.length; i++) {
						if (field.getType().getName().equals(types[i].getName())) {
							fieldValue = newObjectByConstructor(field.getType(),
									new Class<?>[] { String.class }, new Object[] { fieldValue.toString() });
							break;
						}
					}
				}
			}
		} catch (Exception e) {
			logger.error("", e);
		}

		// 设置安全检查，访问私有成员变量必须
		field.setAccessible(true);
		field.set(obj, fieldValue);
		// BeanUtils.copyProperty(dest, filedName, fieldValue);
	}

	public static Field getField(Object obj, String filedName) {
		Field field = null;
		List<Class<?>> list = new ArrayList<Class<?>>();
		getClasses(obj, list);

		for (Class<?> classObj : list) {
			try {
				field = classObj.getDeclaredField(filedName);
				break;
			} catch (SecurityException e) {
				logger.error("", e);
			} catch (NoSuchFieldException e) {
			}
		}

		return field;
	}

	public static void getClasses(Object obj, List<Class<?>> list) {
		Class<?> classObj = null;

		if (obj instanceof Class<?>) {
			classObj = ((Class<?>) obj).getSuperclass();

			if (list.size() == 0) {
				list.add((Class<?>) obj);
			}
		} else {
			classObj = obj.getClass().getSuperclass();

			if (list.size() == 0) {
				list.add(obj.getClass());
			}
		}

		list.add(classObj);

		if (!classObj.getName().equals(Object.class.getName())) {
			getClasses(classObj, list);
		}
	}

	/** */
	/**
	 * 通过构造器取得实例
	 * 
	 * @param className
	 *            类的全限定名
	 * @param intArgsClass
	 *            构造函数的参数类型
	 * @param intArgs
	 *            构造函数的参数值
	 * 
	 * @return Object
	 */
	public static Object newObjectByConstructor(Class<?> classObj, Class<?>[] intArgsClass, Object[] intArgs) {
		Object returnObj = null;
		try {
			// 找到指定的构造方法
			Constructor<?> constructor = classObj.getDeclaredConstructor(intArgsClass);
			// 设置安全检查，访问私有构造函数必须
			constructor.setAccessible(true);
			returnObj = constructor.newInstance(intArgs);
		} catch (Exception e) {
			logger.error("", e);
			e.printStackTrace();
		}

		return returnObj;
	}

	public static Map<String, Field> getFields(Object object) {
		Map<String, Field> map = new HashMap<String, Field>();

		List<Class<?>> list = new ArrayList<Class<?>>();
		getClasses(object, list);

		for (int i = list.size() - 1; i > -1; i--) {
			Field[] fields = list.get(i).getDeclaredFields();
			for (int j = 0; j < fields.length; j++) {
				map.put(fields[j].getName(), fields[j]);
			}
		}

		return map;
	}

	public static void map2Bean(Map<String, Object> map, Object bean) {
		if (bean == null || map == null) {
			return;
		}

		Map<String, Field> fieldMap = getFields(bean);
		if (fieldMap.size() == 0) {
			return;
		}

		Map<String, String> fieldNameMap = new HashMap<String, String>();

		for (String key : fieldMap.keySet()) {
			Field field = fieldMap.get(key);
			field.setAccessible(true);
			String filedName = field.getName();
			fieldNameMap.put(filedName, filedName);
			fieldNameMap.put(filedName.toLowerCase(), filedName);
		}

		for (String key : map.keySet()) {
			Object value = map.get(key);

			String filedName = fieldNameMap.get(key.toLowerCase());
			if (filedName == null) {
				key = key.replace("_", "");
				filedName = fieldNameMap.get(key.toLowerCase());
			}

			if (filedName != null) {
				try {
					setFieldValue(bean, filedName, value);
				} catch (Exception e) {
					logger.error("", e);
				}
			}
		}
	}

	/**
	 * 以Object的字段为key，值为value生成一个map
	 * 
	 * @param map
	 * @param bean
	 * 
	 * @author Jay.Wu
	 */
	public static void bean2Map(Map<String, Object> map, Object bean) {
		if (bean == null || map == null) {
			return;
		}

		Map<String, Field> fieldMap = getFields(bean);
		if (fieldMap.size() == 0) {
			return;
		}

		for (String key : fieldMap.keySet()) {
			map.put(key, getFieldValue(bean, key));
		}
	}

	public static Class<?> string2Class(String simpleClass) {
		if (simpleClass == null) {
			return null;
		}

		if (simpleClass.equalsIgnoreCase("boolean")) {
			return Boolean.class;
		} else if (simpleClass.equalsIgnoreCase("int")) {
			return Integer.class;
		} else if (simpleClass.equalsIgnoreCase("long")) {
			return Long.class;
		} else if (simpleClass.equalsIgnoreCase("double")) {
			return Double.class;
		} else if (simpleClass.equalsIgnoreCase("date")) {
			return Date.class;
		}

		return String.class;
	}
	
	/**
	 * 规范化map的数据，不能是自定义对象和长度不能超过255
	 * @param variables
	 *
	 * @author Luvek.Lu
	 */
	public static void standardlizeMap(Map<String, Object> variables, int maxLength) {
		for (String key : variables.keySet()) {
			Object obj = variables.get(key);
			if (!isLegalClass(obj) || obj.toString().length() > maxLength) {
				// logger.debug(key + "是不合法数据");
				variables.put(key, null);
			}
		}
	}
	
	/**
	 * 判断是否是常用的那几个类型
	 * @param obj
	 * @return
	 *
	 * @author Luvek.Lu
	 */
	public static boolean isLegalClass(Object obj){
		if(obj == null){
			return false;
		}
		
		String typeName = obj.getClass().getSimpleName();
		String[] legalTypes = {"String","Date","TimeStamp","Long","Integer","Double","BigDecimal","Float","Boolean"};
		if(StringUtil.in(legalTypes, typeName, true)){
			return true;
		}
		return false;
	}
}
